Auto Type

타입 추론
C++ 컴파일러는 C++03에서 함수 템플릿의 인수 타입을 자동으로 추론한다.
auto 변수 타입
auto타입을 사용한다고 해도, C++의 엄격한 타입 제한은 바뀌지 않는다.
(auto 타입은 python과 같은 동적 타입과는 다르다. 파이썬에서는 a의 타입을 할당된 표현식의 타입으로 변경한다.)

C++11에서는 변수 a는 표현식의 결과 타입을 가지며, 이 후 해당 타입은 바뀌지 않는다.
자동 타입이 아닌, 한 번 정해진 뒤에는 변하지 않는 타입

auto를 통해서 초기화 되지 않은 변수 선언 불가
auto a=f(g(x, y, z)+3*x);
동일한 타입의 표현식으로 초기화되어 있는 명령문은 auto 변수를 여러개 선언할 수 있다.
auto i=2*7.5, j=std::sqrt(3.7); // double
auto i=2*4, j=std::sqrt(3.7); // error: i int, j double
auto i=2*4, j; // error: j
const 및 레퍼런스 속성을 이용해서 auto를 한정할 수 있다.
auto v=g(x, y, z); // g
auto& ri=i; // i
const auto& cri=i; // i const
auto&& ur=g(x, y, z); // g
v는 g가 레퍼런스를 반환하더라도, 변수 v는 레퍼런스가 아니다.
유니버설 레퍼런스 ur또한 g의 결과가 Rvalue 레퍼런스 혹은 Lvalue 레퍼런스인가에 따라
Rvalue 레퍼런스 혹은 Lvalue 레퍼런스가 된다.
표현식의 타입(decltype)
C++11 부터 decltype 키워드를 지원한다.
decltype는 함수가 반환하는 타입을 표현할 수 있다.
decltype(f(g(x, y, z)+3*x)) a=f(g(x, y, z)+3*x);
decltype은 명시적 타입이 필요한 경우, 유용하게 사용된다.
template <typename Vector1, typename Vec2>
auto operator+(const Vector1& v1, const Vector2& v2)
->vector<decltype(v1[0]+v2[0])>;
위와 같이 decltype를 이용하면, 리턴 타입 추적(Trailing Retrun Type)을 할 수 있다.
(C++11에서는 모든 함수의 리턴 타입을 선언해 주어야 함)

decltype을 사용하면, 함수 인수로 표현할 수 있으며 리턴 타입의 선언을 인수 뒤로 옮길 수 있다.

decltype은 타입 수준에서만 동작하며 인수로 전달한 표현식을 계산하지 않는다.
따라서 위에서 v1[0]을 수행하지 않고 타입만 결정한다.(빈 벡터라도 오류가 발생하지 않음)

decltype의 강력한 기능을 통해 고급 제네릭 프로그래밍 및 메타 프로그래밍에서 이점을 가짐
auto & decltype
auto는 함수 템플릿 매개변수의 규칙을 따르며, 레퍼런스 및 const 한정자를 삭제한다.
decltype은 표현식 타입을 그대로 사용한다.

만일 f가 int&를 반환하는 경우,
auto a=f(x); // a int
decltype(f(x)) a; // a int&
decltype(auto)
decltype에서 표현식( (f(g(x, y, z,)+3*x)) )이 길 경우, decltype(auto)를 사용해서 축약할 수 있다.
decltype(expr) v=expr;
decltype(auto) v=expr; //
자동 리턴 타입
template <typename Vector>
class value_range_vector{
using value_type=typename Vector::value_type;
using size_type=typename Vector::size_type;
public:
value_range_vector(Vector& vref, value_type minv, value_type maxv)
: vref(vref), minv(minv), maxv(maxv) {}
decltype(auto) operator[](size_type t){
decltype(auto) value=vref[i];
if(value<minv) throw too_small{};
if(value>maxv) throw too_large{};
return value;
}
private:
Vector& vref;
value_type minv, maxv;
};
int main(void){
using Vec=mtl::vector<double>;
Vec v={2.3, 8.1, 9.2};
value_range_vector<Vec> w(v, 1.0, 10.0);
decltype(auto) val=w[i];
return 0;
}
위 예제에서 val은 double& 타입이다.
만일 위의 코드에서 decltype(auto)를 auto로 변경하게 되면,
val은 double 타입이 된다.
타입 정의
typedef와 using을 사용해서 타입을 정의할 수 있다.

typedef는 C에도 존재하기 때문에 호환할 수 있다.
C++11 이후의 컴파일러에서는 using을 사용하는 것이 좋다.
typedef double value_type;
using value_type=double;
typedef double dal[10];
using dal=double[10];
typedef는 새로운 이름이 오른쪽에 위치하며, using은 왼쪽에 존재한다.

배열을 선언할 때, using을 사용하면, 배열의 타입이 하나의 조각안에 존재함
typedef float float_fun1(float, int);
using float_func1=float(float, int);
이와 같이 using 선언은 새로운 타입과 변수의 이름을 명확하게 구분한다.
템플릿 에일리어스(Template Alias)
템플릿 에일리어스는 타입 매개변수를 갖는 정의이다.
template <unsigned Order, typename Value>
class tensor{ ... };
template <typename Value>
using vector=tensor<1, Value>;
template <typename Value>
using matrix=tensor<2, Value>;
int main(void){
std::cout<<"type of vector<float> is "<<typeid(vector<float>).name()<<'\n';
std::cout<<"type of matrix<float> is "<<typeid(matrix<float>).name()<<'\n';
}
템플릿 에일리어스는 typedef로는 불가능하지만, using을 사용하면 쉽게 만들 수 있다.

typedef는 템플릿을 지원하지 않지만, using은 템플릿을 지원함